<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';

// 声明 SpeechRecognition 类型
interface SpeechRecognitionEvent extends Event {
  results: {
    [index: number]: {
      [index: number]: {
        transcript: string;
      };
      isFinal: boolean;
    };
    length: number;
  };
  resultIndex: number;
}

interface SpeechRecognitionErrorEvent extends Event {
  error: string;
}

interface SpeechRecognition extends EventTarget {
  continuous: boolean;
  interimResults: boolean;
  lang: string;
  start(): void;
  stop(): void;
  abort(): void;
  onresult: (event: SpeechRecognitionEvent) => void;
  onerror: (event: SpeechRecognitionErrorEvent) => void;
  onend: () => void;
  stream: MediaStream;
}

declare global {
  interface Window {
    SpeechRecognition: new () => SpeechRecognition;
    webkitSpeechRecognition: new () => SpeechRecognition;
  }
}

// 语音识别相关状态
const isListening = ref(false);
const inputText = ref('');
const interimResult = ref('');
const recognition = ref<SpeechRecognition | null>(null);
const recordingTime = ref(0);
const timerInterval = ref<number | null>(null);

// 初始化语音识别
onMounted(() => {
  // 创建语音识别实例（兼容不同浏览器）
  const SpeechRecognition =
    window.SpeechRecognition || window.webkitSpeechRecognition;

  if (!SpeechRecognition) {
    alert('您的浏览器不支持语音识别功能，请使用Chrome、Edge或Safari浏览器。');
    return;
  }

  recognition.value = new SpeechRecognition();

  // 配置语音识别
  recognition.value.continuous = true; // 持续识别
  recognition.value.interimResults = true; // 返回临时结果
  recognition.value.lang = 'zh-CN'; // 设置语言为中文

  // 处理识别结果
  recognition.value.onresult = (event) => {
    let finalTranscript = '';
    let interimTranscript = '';

    for (let i = event.resultIndex; i < event.results.length; i++) {
      const transcript = event.results[i][0].transcript;

      if (event.results[i].isFinal) {
        finalTranscript += transcript;
      } else {
        interimTranscript += transcript;
      }
    }

    // 更新最终结果和临时结果
    if (finalTranscript) {
      inputText.value += finalTranscript;
    }
    interimResult.value = interimTranscript;
  };

  // 处理识别结束事件
  recognition.value.onend = () => {
    // 如果仍处于监听状态，则重新开始识别
    if (isListening.value) {
      recognition.value?.start();
    } else {
      stopListening();
    }
  };

  // 处理错误
  recognition.value.onerror = (event) => {
    console.error('语音识别错误:', event.error);
    if (event.error === 'not-allowed') {
      alert('无法访问麦克风，请确保已授予麦克风权限。');
      stopListening();
    }
  };
});

// 开始语音识别
const startListening = () => {
  if (!recognition.value) return;

  try {
    recognition.value.start();
    isListening.value = true;

    // 开始计时
    recordingTime.value = 0;
    timerInterval.value = window.setInterval(() => {
      recordingTime.value += 1;
    }, 1000);
  } catch (error) {
    console.error('语音识别启动失败:', error);
  }
};

// 停止语音识别
const stopListening = () => {
  if (!recognition.value) return;

  try {
    recognition.value.stop();
    isListening.value = false;
    interimResult.value = '';

    // 停止计时
    if (timerInterval.value) {
      clearInterval(timerInterval.value);
      timerInterval.value = null;
    }
  } catch (error) {
    console.error('语音识别停止失败:', error);
  }
};

// 切换语音识别状态
const toggleListening = () => {
  if (isListening.value) {
    stopListening();
  } else {
    startListening();
  }
};

// 格式化时间
const formatTime = (seconds: number): string => {
  const minutes = Math.floor(seconds / 60);
  const remainingSeconds = seconds % 60;
  return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`;
};

// 组件卸载时清理资源
onUnmounted(() => {
  if (timerInterval.value) {
    clearInterval(timerInterval.value);
  }

  if (recognition.value && isListening.value) {
    recognition.value.stop();
  }
});
</script>

<template>
  <div class="voice-input-container p-6 max-w-md mx-auto">
    <h1 class="text-2xl font-bold mb-6 text-center">语音输入</h1>

    <div class="input-container mb-6">
      <div class="relative">
        <textarea
          v-model="inputText"
          class="w-full p-3 pr-10 border rounded-lg min-h-[120px] resize-none focus:outline-none focus:ring-2 focus:ring-blue-500"
          placeholder="点击麦克风按钮开始语音输入..."
        ></textarea>

        <!-- 清空按钮 -->
        <button
          v-if="inputText"
          class="absolute right-3 top-3 text-gray-400 hover:text-gray-600"
          title="清空输入"
          @click="inputText = ''"
        >
          <svg
            xmlns="http://www.w3.org/2000/svg"
            class="h-5 w-5"
            viewBox="0 0 20 20"
            fill="currentColor"
          >
            <path
              fill-rule="evenodd"
              d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
              clip-rule="evenodd"
            />
          </svg>
        </button>
      </div>

      <!-- 临时识别结果 -->
      <div
        v-if="interimResult"
        class="mt-2 p-2 bg-gray-50 rounded text-gray-500 italic"
      >
        {{ interimResult }}
      </div>
    </div>

    <div class="status-bar mb-4 p-3 rounded-lg bg-gray-100">
      <div class="flex items-center justify-between">
        <div class="flex items-center">
          <div
            class="w-3 h-3 rounded-full mr-2"
            :class="isListening ? 'bg-red-500 animate-pulse' : 'bg-gray-400'"
          ></div>
          <span>{{ isListening ? '正在聆听...' : '未在聆听' }}</span>
        </div>
        <div v-if="isListening" class="recording-time">
          {{ formatTime(recordingTime) }}
        </div>
      </div>
    </div>

    <div class="controls flex gap-4">
      <button
        class="flex-1 py-3 px-4 rounded-lg font-medium transition-colors flex items-center justify-center"
        :class="
          isListening ? 'bg-red-100 text-red-700' : 'bg-blue-100 text-blue-700'
        "
        @click="toggleListening"
      >
        <svg
          xmlns="http://www.w3.org/2000/svg"
          class="h-5 w-5 mr-2"
          viewBox="0 0 20 20"
          fill="currentColor"
        >
          <path
            fill-rule="evenodd"
            d="M7 4a3 3 0 016 0v4a3 3 0 11-6 0V4zm4 10.93A7.001 7.001 0 0017 8a1 1 0 10-2 0A5 5 0 015 8a1 1 0 00-2 0 7.001 7.001 0 006 6.93V17H6a1 1 0 100 2h8a1 1 0 100-2h-3v-2.07z"
            clip-rule="evenodd"
          />
        </svg>
        {{ isListening ? '停止语音输入' : '开始语音输入' }}
      </button>
    </div>
  </div>
</template>

<style scoped>
@reference "tailwindcss";

.voice-input-container {
  @apply bg-white rounded-xl shadow-md;
}

.controls button:focus {
  @apply outline-none ring-2 ring-offset-2 ring-blue-500;
}

textarea {
  @apply transition-all duration-200;
}

textarea:focus {
  @apply shadow-sm;
}

.status-bar {
  @apply transition-all duration-300;
}
</style>
